package com.fau.wmbj.server.storage;

import com.fau.wmbj.server.entity.User;
import com.fau.wmbj.server.service.SysConfigService;
import com.fau.wmbj.server.service.UserService;
import com.fau.wmbj.server.utils.Message;
import com.fau.wmbj.server.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletContext;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * Service - 文件
 *
 * @author jiawei
 * @version 1.0
 * @datetime 2019/7/29 10:43
 **/
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
@Service("fileServiceImpl")
public class StorageServiceImpl implements StorageService {

    private final static Logger logger = LoggerFactory.getLogger(StorageServiceImpl.class);
    private final static String UPLOAD_TEMP_PATH = "/temp/base64";
    private final ServletContext servletContext;
    private final TaskExecutor taskExecutor;
    private final StorageConfigService storageConfigService;
    private final StorageDirectoryService storageDirectoryService;
    private final StorageService storageService;
    private final UserService userService;
    private final SysConfigService sysConfigService;


    /**
     * 添加文件上传任务
     *
     * @param storagePlugin 存储插件
     * @param path          上传路径
     * @param file          上传文件
     * @param contentType   文件类型
     */
    private void addUploadTask(final Storage storagePlugin, final String path, final File file, final String contentType, boolean open) {
        taskExecutor.execute(() -> {
            try {
                upload(storagePlugin, path, file, contentType, open);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }


    /**
     * 上传文件
     *
     * @param storagePlugin 存储插件
     * @param path          上传路径
     * @param file          上传文件
     * @param contentType   文件类型
     */
    private void upload(Storage storagePlugin, String path, File file, String contentType, boolean open) throws Exception {
        Assert.notNull(storagePlugin, "[Assertion failed] - storagePlugin is required; it must not be null");
        Assert.hasText(path, "[Assertion failed] - path must have text; it must not be null, empty, or blank");
        Assert.notNull(file, "[Assertion failed] - file is required; it must not be null");
        try {
            storagePlugin.upload(path, file, contentType, open);
        } finally {
            FileUtils.forceDelete(file);
        }
    }

    @Override
    public Message uploadChunk(MultipartFile file, Boolean preview, String tableName, Long tableId, String fileMd5, Integer chunk, Integer chunkCount, Integer chunkSize, boolean async) throws Exception {
        Assert.notNull(file, "[Assertion failed] - file is required; it must not be null");
        Assert.notNull(fileMd5, "[Assertion failed] - fileMd5 is required; it must not be null");
        Assert.notNull(chunk, "[Assertion failed] - chunk is required; it must not be null");
        Assert.notNull(chunkCount, "[Assertion failed] - chunkCount is required; it must not be null");
        Assert.notNull(chunkSize, "[Assertion failed] - chunkSize is required; it must not be null");
        String noGroupPath = "";
        Message message = null;
//        String chunklockName = SystemConfig.CHUNK_LOCK_CACHE_NAME + fileMd5;
//        boolean currOwner = false;
//        logger.info("共{}片,第{}片文件上传", chunkCount, chunk);
//        List<StoragePlugin> storagePlugins = pluginService.getStoragePlugins(true);
//        Assert.notEmpty(storagePlugins);
//        StoragePlugin storagePlugin = storagePlugins.get(0);
//        try {
//            Long lock = RedisCacheUtil.incr(chunklockName);
//            if (lock > 1) {
//                message = Message.error("请求块锁失败");
//            }
//            currOwner = true;
//            //redis中记录当前应该穿第几块(从0开始)
//            String chunkCurrkey = SystemConfig.CHUNK_CURR_CACHE_NAME + fileMd5;
//            String chunkCurr = RedisCacheUtil.getString(chunkCurrkey);
//
//            if (StringUtils.isEmpty(chunkCurr)) {
//                message = Message.error("无法获取当前文件chunkCurr");
//            }
//
//            Integer chunkCurr_int = Integer.parseInt(chunkCurr);
//            if (chunk < chunkCurr_int) {
//                message = Message.error("当前文件块已上传");
//            } else if (chunk > chunkCurr_int) {
//                message = Message.error("当前文件块需要等待上传,稍后请重试");
//            }
//
//            String extension = FilenameUtils.getExtension(file.getOriginalFilename());
//            if (!file.isEmpty()) {
//                try {
//                    //获取已经上传文件大小
//                    Long historyUpload = 0L;
//                    String historyUploadStr = RedisCacheUtil.getString(SystemConfig.FILE_UPLOAD_HISTORY_UPLOAD_CACHE_NAME + fileMd5);
//                    if (StringUtils.isNotEmpty(historyUploadStr)) {
//                        historyUpload = Long.parseLong(historyUploadStr);
//                    }
//
//                    Map<String, Object> model = new HashMap<>(16);
//                    model.put("ext", extension);
//                    Setting setting = SystemUtils.getSetting();
//                    String resolveUploadPath = setting.resolveUploadPath(model);
//                    String destPath = resolveUploadPath + fileMd5 + admin.getMobile() + SystemConfig.SPLIT_1 + extension;
//                    if (chunk == 0) {
//                        Integer add = chunkCurr_int + 1;
//                        RedisCacheUtil.setString(chunkCurrkey, add.toString());
//
//                        if (storagePlugin instanceof FastDFSStoragePlugin) {
//                            try {
//                                StorePath path = appendFileStorageClient.uploadAppenderFile("group1", file.getInputStream(),
//                                        file.getSize(), extension);
//                                if (path == null) {
//                                    RedisCacheUtil.setString(chunkCurrkey, chunkCurr_int.toString());
//                                    message = Message.error("获取远程文件路径出错");
//                                }
//                                noGroupPath = path.getPath();
//                                RedisCacheUtil.setString(SystemConfig.FASTDFS_PATH_CACHE_NAME + fileMd5, path.getPath());
//                            } catch (Exception e) {
//                                RedisCacheUtil.setString(chunkCurrkey, chunkCurr_int.toString());
//                                message = Message.error("上传远程服务器文件出错");
//                            }
//                        } else if (storagePlugin instanceof OssStorage) {
//                            String endpoint = storagePlugin.getAttribute("endpoint");
//                            String accessId = storagePlugin.getAttribute("accessId");
//                            String accessKey = storagePlugin.getAttribute("accessKey");
//                            String bucketName = storagePlugin.getAttribute("bucketName");
//                            try {
//                                OSSClient ossClient = new OSSClient(endpoint, accessId, accessKey);
//                                InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, destPath);
//                                InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
//                                String uploadId = upresult.getUploadId();
//                                InputStream instream = file.getInputStream();
//                                UploadPartRequest uploadPartRequest = new UploadPartRequest();
//                                uploadPartRequest.setBucketName(bucketName);
//                                uploadPartRequest.setKey(destPath);
//                                uploadPartRequest.setUploadId(uploadId);
//                                uploadPartRequest.setInputStream(instream);
//                                // 设置分片大小。除了最后一个分片没有大小限制，其他的分片最小为100 KB。
//                                uploadPartRequest.setPartSize(file.getSize());
//                                // 设置分片号。每一个上传的分片都有一个分片号，取值范围是1~10000，如果超出这个范围，OSS将返回InvalidArgument的错误码。
//                                uploadPartRequest.setPartNumber(chunk + 1);
//                                // 每个分片不需要按顺序上传，甚至可以在不同客户端上传，OSS会按照分片号排序组成完整的文件。
//                                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
//                                //OSS的返回结果包含PartETag。
//                                uploadPartResult.getPartETag();
//                                if (chunk + 1 == chunkCount) {
//                                    List<PartETag> partETags = new ArrayList<>();
//                                    ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, destPath, uploadId);
//                                    PartListing partListing = ossClient.listParts(listPartsRequest);
//                                    for (PartSummary part : partListing.getParts()) {
//                                        partETags.add(new PartETag(part.getPartNumber(), part.getETag()));
//                                    }
//                                    CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, destPath, uploadId, partETags);
//                                    // 如果需要在完成文件上传的同时设置文件访问权限，请参考以下示例代码。
//                                    // completeMultipartUploadRequest.setObjectACL(CannedAccessControlList.PublicRead);
//                                    // 完成上传。
//                                    CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
//                                }
//                                //关闭OSSClient。
//                                ossClient.shutdown();
//                                RedisCacheUtil.setString(SystemConfig.FASTDFS_PATH_CACHE_NAME + fileMd5, uploadId);
//                            } catch (Exception e) {
//                                RedisCacheUtil.setString(chunkCurrkey, chunkCurr_int.toString());
//                                message = Message.error("获取远程文件路径出错");
//                                e.printStackTrace();
//                                throw new Exception(e.getMessage(), e);
//                            }
//                        }
//                    } else {
//                        Integer add = chunkCurr_int + 1;
//                        RedisCacheUtil.setString(chunkCurrkey, add.toString());
//                        String uploadId = RedisCacheUtil.getString(SystemConfig.FASTDFS_PATH_CACHE_NAME + fileMd5);
//                        if (uploadId == null) {
//                            message = Message.error("无法获取上传远程服务器文件出错");
//                        }
//                        try {
//                            if (storagePlugin instanceof FastDFSStoragePlugin) {
//                                String fastDFSGroup = storagePlugin.getAttribute("fastDFSGroup");
//                                //追加方式实际实用如果中途出错多次,可能会出现重复追加情况,这里改成修改模式,即时多次传来重复文件块,依然可以保证文件拼接正确
//                                appendFileStorageClient.modifyFile(fastDFSGroup, uploadId, file.getInputStream(),
//                                        file.getSize(), historyUpload);
//                            } else if (storagePlugin instanceof OssStorage) {
//                                String endpoint = storagePlugin.getAttribute("endpoint");
//                                String accessId = storagePlugin.getAttribute("accessId");
//                                String accessKey = storagePlugin.getAttribute("accessKey");
//                                String bucketName = storagePlugin.getAttribute("bucketName");
//                                try {
//                                    List<PartETag> partETags = new ArrayList<>();
//                                    OSSClient ossClient = new OSSClient(endpoint, accessId, accessKey);
//                                    InputStream instream = file.getInputStream();
//                                    UploadPartRequest uploadPartRequest = new UploadPartRequest();
//                                    uploadPartRequest.setBucketName(bucketName);
//                                    uploadPartRequest.setKey(destPath);
//                                    uploadPartRequest.setUploadId(uploadId);
//                                    uploadPartRequest.setInputStream(instream);
//                                    // 设置分片大小。除了最后一个分片没有大小限制，其他的分片最小为100 KB。
//                                    uploadPartRequest.setPartSize(file.getSize());
//                                    // 设置分片号。每一个上传的分片都有一个分片号，取值范围是1~10000，如果超出这个范围，OSS将返回InvalidArgument的错误码。
//                                    uploadPartRequest.setPartNumber(chunk + 1);
//                                    // 每个分片不需要按顺序上传，甚至可以在不同客户端上传，OSS会按照分片号排序组成完整的文件。
//                                    UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
//                                    //OSS的返回结果包含PartETag。
//                                    uploadPartResult.getPartETag();
//                                    if (chunk + 1 == chunkCount) {
//                                        ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, destPath, uploadId);
//                                        PartListing partListing = ossClient.listParts(listPartsRequest);
//                                        for (PartSummary part : partListing.getParts()) {
//                                            partETags.add(new PartETag(part.getPartNumber(), part.getETag()));
//                                        }
//                                        CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, destPath, uploadId, partETags);
//                                        // 如果需要在完成文件上传的同时设置文件访问权限，请参考以下示例代码。
//                                        // completeMultipartUploadRequest.setObjectACL(CannedAccessControlList.PublicRead);
//                                        // 完成上传。
//                                        CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
//                                    }
//                                    // 关闭OSSClient。
//                                    ossClient.shutdown();
//
//                                } catch (Exception e) {
//                                    e.printStackTrace();
//                                    throw new Exception(e.getMessage(), e);
//                                }
//                            }
//                        } catch (Exception e) {
//                            e.printStackTrace();
//                            RedisCacheUtil.setString(chunkCurrkey, chunkCurr_int.toString());
//                            message = Message.error("更新远程文件出错");
//                        }
//                    }
//                    //修改历史上传大小
//                    historyUpload = historyUpload + file.getSize();
//                    RedisCacheUtil.set(SystemConfig.FILE_UPLOAD_HISTORY_UPLOAD_CACHE_NAME + fileMd5, historyUpload.toString());
//                    //最后一块,清空upload,写入数据库
//                    if (chunk + 1 == chunkCount) {
//                        FileDetail fileDetail = new FileDetail();
//                        fileDetail.setTableName(tableName);
//                        fileDetail.setTableId(tableId);
//                        fileDetail.setCreatedDate(new Date());
//                        fileDetail.setLastModifiedDate(new Date());
//                        fileDetail.setUserId(admin.getId());
//                        fileDetail.setStorageServer(storagePlugin.getAttribute("urlPrefix"));
//                        fileDetail.setStoragePlugin(storagePlugin.getId());
//                        fileDetail.setFileSize(historyUpload);
//                        fileDetail.setFileName(file.getOriginalFilename());
//                        fileDetail.setFileType(extension);
//                        if (storagePlugin instanceof FastDFSStoragePlugin) {
//                            fileDetail.setUrl(storagePlugin.getUrl(RedisCacheUtil.getString(SystemConfig.FASTDFS_PATH_CACHE_NAME + fileMd5)));
//                            String fastDFSGroup = storagePlugin.getAttribute("fastDFSGroup");
//                            fileDetail.setGroupId(fastDFSGroup);
//                        } else if (storagePlugin instanceof OssStorage) {
//                            String bucketName = storagePlugin.getAttribute("bucketName");
//                            fileDetail.setGroupId(bucketName);
//                            fileDetail.setUrl(destPath);
//                        }
//                        RedisCacheUtil.del(SystemConfig.CHUNK_LOCK_CACHE_NAME + fileMd5);
//                        RedisCacheUtil.del(SystemConfig.CHUNK_CURR_CACHE_NAME + fileMd5);
//                        RedisCacheUtil.del(SystemConfig.FASTDFS_PATH_CACHE_NAME + fileMd5);
//                        RedisCacheUtil.del(SystemConfig.CURR_LOCKS_CACHE_NAME + fileMd5);
//                        RedisCacheUtil.del(SystemConfig.LOCK_OWNER_CACHE_NAME + fileMd5);
//                        RedisCacheUtil.del(SystemConfig.FILE_UPLOAD_HISTORY_UPLOAD_CACHE_NAME + fileMd5);
//                        FileDetail save = fileDetailService.save(fileDetail);
//                        message = Message.success("操作成功", save);
//                    }
//                } catch (Exception e) {
//                    e.printStackTrace();
//                    logger.error("上传文件错误", e);
//                }
//            }
//        } finally {
//            if (currOwner) {
//                if (message != null && message.getType().equals(Message.Type.success)) {
//                } else {
//                    RedisCacheUtil.set(chunklockName, 0);
//                }
//            }
//        }
//        if (message == null) {
//            message = Message.success("操作成功");
//        }
        return message;
    }

    /**
     * 文件上传
     *
     * @param file  上传文件
     * @param async 是否异步
     * @return 访问URL
     */
    @Override
    public String upload(File file, String extension, boolean async, boolean open) throws Exception {
        Assert.notNull(file, "file不能为空");
        String uploadPath = "";
        UUID uuid = UUID.randomUUID();
        String destPath = uploadPath + uuid + "." + extension;
        List<Storage> storagePlugins = storageConfigService.getStoragePlugins(true);
        if (CollectionUtils.isNotEmpty(storagePlugins)) {
            try {
                for (Storage storagePlugin : storagePlugins) {
                    String path = storagePlugin.upload(destPath, file, extension, open);
                    return path;
                }
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        } else {
            throw new Exception("没有可用的上传插件！");
        }
        return null;
    }

    @Override
    public boolean isValid(MultipartFile multipartFile) {
        Assert.notNull(multipartFile, "multipartFile不能为空");
        Assert.state(!multipartFile.isEmpty(), "文件内容不能为空");
        int uploadMaxSize = Integer.parseInt(sysConfigService.getConfigValue("uploadMaxSize"));
        String[] uploadMediaExtensions = sysConfigService.getConfigValue("uploadMediaExtensions").split(",");
        String[] uploadFileExtensions = sysConfigService.getConfigValue("uploadFileExtensions").split(",");
        String[] uploadImageExtensions = sysConfigService.getConfigValue("uploadImageExtensions").split(",");
        if (uploadMaxSize != 0 && multipartFile.getSize() > uploadMaxSize * 1024L * 1024L) {
            return false;
        }
        if (ArrayUtils.isNotEmpty(uploadMediaExtensions)) {
            return FilenameUtils.isExtension(StringUtils.lowerCase(multipartFile.getOriginalFilename()), uploadMediaExtensions);
        }
        if (ArrayUtils.isNotEmpty(uploadFileExtensions)) {
            return FilenameUtils.isExtension(StringUtils.lowerCase(multipartFile.getOriginalFilename()), uploadFileExtensions);
        }
        if (ArrayUtils.isNotEmpty(uploadImageExtensions)) {
            return FilenameUtils.isExtension(StringUtils.lowerCase(multipartFile.getOriginalFilename()), uploadImageExtensions);
        }
        return false;
    }

    @Override
    public StorageDirectory upload(MultipartFile multipartFile, String tableName, Long tableId, boolean open, boolean async) throws Exception {
        Assert.notNull(multipartFile, "multipartFile不能为空");
        Assert.state(!multipartFile.isEmpty(), "文件内容不能为空");
        String extension = FilenameUtils.getExtension(multipartFile.getOriginalFilename());
        UUID uuid = UUID.randomUUID();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd");
        String date = formatter.format(new Date());
        String destPath = "/" + date + "/" + extension + "/" + uuid + "." + extension;
        User current = userService.getCurrentUser();
        List<Storage> storagePlugins = storageConfigService.getStoragePlugins(true);
        if (CollectionUtils.isNotEmpty(storagePlugins)) {
            try {
                for (Storage storagePlugin : storagePlugins) {
                    StorageDirectory fileDetail = new StorageDirectory();
                    fileDetail.setTag(tableName + "_" + tableId);
                    if (current != null) {
                        fileDetail.setUserId(current.getId());
                    }
                    fileDetail.setStorageServer(storagePlugin.getAttribute("urlPrefix"));
                    fileDetail.setStoragePlugin(storagePlugin.getId());
                    fileDetail.setFileSize(multipartFile.getSize());
                    fileDetail.setFileName(FilenameUtils.getName(multipartFile.getOriginalFilename()));
                    fileDetail.setFileType(FilenameUtils.getExtension(multipartFile.getOriginalFilename()));
                    String path = storagePlugin.upload(destPath, multipartFile, open);
                    if (StringUtils.isNotBlank(path)) {
                        fileDetail.setUrl(path);
                        if (storagePlugin instanceof MinioStorage) {
                            String groupId = storagePlugin.getAttribute("bucketName");
                            if (open) {
                                groupId = groupId + "-open";
                            }
                            fileDetail.setGroupId(groupId);
                        } else if (storagePlugin instanceof OssStorage) {
                            String groupId = storagePlugin.getAttribute("bucketName");
                            if (open) {
                                groupId = groupId + "-open";
                            }
                            fileDetail.setGroupId(groupId);
                        } else if (storagePlugin instanceof FastDFSStorage) {
                            String groupId = storagePlugin.getAttribute("fastDFSGroup");
                            if (open) {
                                groupId = groupId + "-open";
                            }
                            fileDetail.setGroupId(groupId);
                        }

                        storageDirectoryService.save(fileDetail);
                        return fileDetail;
                    } else {
                        throw new Exception("上传失败");
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        } else {
            throw new Exception("没有可用的上传插件！");
        }
        return null;
    }

    @Override
    public StorageDirectory uploadBase64(String imgType, String imgBase, String tableName, Long tableId, boolean async) throws IOException {

        // File dir = new File(Constants.REALPATH + UPLOAD_TEMP_PATH);
        // if (!dir.exists()) {
        //     dir.mkdirs();
        // }
        // String uuid = UUID.randomUUID().toString();
        // String fileName = uuid + Constants.SPLIT_1 + imgType;
        // String destPath = Constants.REALPATH + UPLOAD_TEMP_PATH + Constants.DELIMITER + fileName;
        // FileOutputStream out = null;
        // InputStream in = null;
        // try {
        //     byte[] bytes = new BASE64Decoder().decodeBuffer(imgBase);
        //     for (int i = 0; i < bytes.length; ++i) {
        //         if (bytes[i] < 0) {// 调整异常数据
        //             bytes[i] += 256;
        //         }
        //     }
        //     out = new FileOutputStream(destPath);
        //     out.write(bytes);
        //     out.flush();
        //     out.close();
        //     File file = new File(destPath);
        //     in = Files.newInputStream(file.toPath());
        //     MultipartFile multipartFile2 = new MockMultipartFile(uuid, fileName, imgType, in);
        //     FileDetail fileDetail = upload(multipartFile2, tableName, tableId, async);
        //     file.delete();
        //     return fileDetail;
        // } catch (IOException e) {
        //     logger.error(e.getMessage(), e);
        // } catch (Exception e) {
        //     e.printStackTrace();
        // }
        return null;
    }

    @Override
    public StorageDirectory upload(MultipartFile multipartFile, String tableName, Long tableId, boolean open) throws Exception {
        Assert.notNull(multipartFile, "multipartFile不能为空");
        Assert.state(!multipartFile.isEmpty(), "文件内容不能为空");
        return upload(multipartFile, tableName, tableId, open, false);
    }

    @Override
    public String upload(MultipartFile multipartFile) throws Exception {
        Assert.notNull(multipartFile, "multipartFile不能为空");
        Assert.state(!multipartFile.isEmpty(), "文件内容不能为空");
        String extension = FilenameUtils.getExtension(multipartFile.getOriginalFilename());
        UUID uuid = UUID.randomUUID();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd");
        String date = formatter.format(new Date());
        String destPath = "/" + date + "/" + extension + "/" + uuid + "." + extension;
        User current = userService.getCurrentUser();
        List<Storage> storagePlugins = storageConfigService.getStoragePlugins(true);
        if (CollectionUtils.isNotEmpty(storagePlugins)) {
            try {
                for (Storage storage : storagePlugins) {
                    String path = storage.upload(destPath, multipartFile, true);
                    if (StringUtils.isNotBlank(path)) {
                        return storage.getAttribute("urlPrefix") + path;
                    } else {
                        throw new Exception("上传失败");
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        } else {
            throw new Exception("没有可用的上传插件！");
        }
        return null;
    }

    @Override
    public String uploadLocal(MultipartFile multipartFile) {
        Assert.notNull(multipartFile, "multipartFile不能为空");
        Assert.state(!multipartFile.isEmpty(), "文件内容不能为空");


        String extension = FilenameUtils.getExtension(multipartFile.getOriginalFilename()).toLowerCase();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String date = formatter.format(new Date());
        String uploadPath = "/" + date + "/" + extension + "/";


        try {
            String destPath = uploadPath + UUID.randomUUID() + "." + extension;
            File destFile = new File(destPath);
            File destDir = destFile.getParentFile();
            if (destDir != null) {
                destDir.mkdirs();
            }
            multipartFile.transferTo(destFile);
            return destPath;
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    @Override
    public boolean delete(String url, String groupId, String storagePluginId, boolean async) {
        Assert.notNull(storagePluginId, "storagePluginId不能为空");
        Assert.hasText(url, "url不能为空");
        if (async) {
            addDeleteTask(url, groupId, storagePluginId);
        } else {
            delete(url, groupId, storagePluginId);
        }
        return true;
    }

    @Override
    public void delete(StorageDirectory fileDetail, boolean async) {
        Assert.notNull(fileDetail, "fileDetail不能为空");
        if (async) {
            addDeleteTask(fileDetail);
        } else {
            delete(fileDetail);
        }
    }

    @Override
    public InputStream download(StorageDirectory fileDetail, Boolean isPreview) {
        if (fileDetail != null && StringUtils.isNotBlank(fileDetail.getUrl()) && StringUtils.isNotBlank(fileDetail.getStoragePlugin())) {
            Storage storagePlugin = storageConfigService.getStorage(fileDetail.getStoragePlugin());
            return storagePlugin.download(fileDetail, isPreview);
        }
        return null;
    }

    @Override
    public String getUrl(StorageDirectory fileDetail, boolean isPreview, int timeOut) {
        if (fileDetail != null) {
            String storagePluginId = fileDetail.getStoragePlugin();
            if (org.apache.commons.lang3.StringUtils.isNotBlank(storagePluginId)) {
                Storage storagePlugin = storageConfigService.getStorage(storagePluginId);
                if (storagePlugin != null) {
                    return storagePlugin.getUrl(fileDetail, isPreview, timeOut);
                }
            }
        }
        return null;
    }

    @Override
    public void clearTempFile() {
        String tempPath = "/temp";
        File tempFolder = new File(Constants.REALPATH + tempPath);
        if (tempFolder.exists()) {
            File[] files = tempFolder.listFiles();
            for (File file : files) {
                delAllFile(file);
            }
        }
    }

    private void delAllFile(File file) {
        if (!file.exists()) {
            return;
        }
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (ArrayUtils.isNotEmpty(files)) {
                for (File file1 : files) {
                    delAllFile(file1);
                }
            } else {
                file.delete();
            }
        } else {
            file.delete();
        }
        return;
    }

    /**
     * 添加文件删除任务
     *
     * @param fileDetail 文件信息
     */
    private void addDeleteTask(final StorageDirectory fileDetail) {
        taskExecutor.execute(() -> delete(fileDetail));
    }

    /**
     * 添加文件删除任务
     *
     * @param url 上传路径
     */
    private void addDeleteTask(final String url, final String groupId, final String storagePluginId) {
        taskExecutor.execute(() -> delete(url, groupId, storagePluginId));
    }

    /**
     * 删除文件
     */
    private void delete(StorageDirectory fileDetail) {
        String storagePluginId = fileDetail.getStoragePlugin();
        if (StringUtils.isNotBlank(storagePluginId)) {
            Storage storagePlugin = storageConfigService.getStorage(storagePluginId);
            if (storagePlugin != null) {
                storagePlugin.delete(fileDetail, false);
                storagePlugin.delete(fileDetail, true);
            }
        }
    }

    /**
     * 删除文件
     */
    private void delete(String url, String groupId, String storagePluginId) {
        Storage storagePlugin = storageConfigService.getStorage(storagePluginId);
        if (storagePlugin != null) {
            storagePlugin.delete(url, groupId);
        }
    }

    private boolean deleteFile(File file) {
        if (!file.exists()) {
            return false;
        }
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
                deleteFile(f);
            }
        }
        return file.delete();
    }

}